package com.qys.livesMall.anchor.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qys.livesMall.anchor.mapper.AnchorLivesRoomMapper;
import com.qys.livesMall.anchor.mapper.AnchorLivesSessionMapper;
import com.qys.livesMall.anchor.mapper.H2AnchorMapper;
import com.qys.livesMall.anchor.model.dto.lives.app.AnchorLivesDTO;
import com.qys.livesMall.anchor.model.entity.AnchorLivesRoom;
import com.qys.livesMall.anchor.model.entity.AnchorLivesSession;
import com.qys.livesMall.anchor.model.entity.H2Anchor;
import com.qys.livesMall.anchor.model.vo.lives.app.AnchorLivesVO;
import com.qys.livesMall.anchor.service.AnchorLivesRoomService;
import com.qys.livesMall.app.user.model.entity.H2AppUser;
import com.qys.livesMall.app.user.service.IH2AppUserService;
import com.qys.livesMall.cache.utils.CacheUtils;
import com.qys.livesMall.common.exception.QysException;
import com.qys.livesMall.common.utils.MessageUtils;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

import static com.qys.livesMall.anchor.constants.RedisConstant.ANCHOR_CREATE_LIVES_ROOM_DELAY;

/**
 * <p>
 * 主播直播间表 服务实现类
 * </p>
 *
 * @author wzy
 * @since 2023-06-26
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AnchorLivesRoomServiceImpl extends ServiceImpl<AnchorLivesRoomMapper, AnchorLivesRoom> implements AnchorLivesRoomService {

    private final CacheUtils cacheUtils;
    @Resource
    private  H2AnchorMapper anchorMapper;
    private final IH2AppUserService appUserService;
    @Resource
    private AnchorLivesSessionMapper livesSessionMapper;


    /**
     * 初始化直播间
     *
     * @param anchorId 主播id
     * @return 是否初始化成功
     */
    @Override
    public AnchorLivesRoom initLivesRoom(Long anchorId) {
        AnchorLivesRoom anchorLivesRoom = getOne(Wrappers.<AnchorLivesRoom>lambdaQuery().eq(AnchorLivesRoom::getAnchorId, anchorId).last("limit 1"));
        if (anchorLivesRoom!=null){
            return anchorLivesRoom;
        }else {
            anchorLivesRoom=new AnchorLivesRoom();
        }
        String lockName = ANCHOR_CREATE_LIVES_ROOM_DELAY + anchorId;
        //获取锁信息
        boolean isLock = false;
        try {

            int count = 1;
            while (!isLock) {
                if (count == 10) {
                    throw new QysException(MessageUtils.message("system.error"));
                }
                //获得锁
                isLock = cacheUtils.getLock(lockName, CacheUtils.LOCK_WAITTIME_SECONDS);
                count++;
            }
            anchorLivesRoom.setLivesRoomNum(getLivesRoomNum());
            anchorLivesRoom.setAnchorId(anchorId);
            anchorLivesRoom.setAnchorName(anchorMapper.selectById(anchorId).getAnchorName());
            anchorLivesRoom.setLiveStatus((byte) 1);
            anchorLivesRoom.setStatus((byte) 0);
            anchorLivesRoom.setCreateTime(LocalDateTime.now());
            anchorLivesRoom.setLastLiveTime(null);
            baseMapper.insert(anchorLivesRoom);
        } finally {
            if (isLock) {
                //释放锁
                cacheUtils.releaseLock(lockName);
            }
        }
        return anchorLivesRoom;
    }

    /**
     * 根据直播间id查询直播间
     *
     * @param anchorId
     */
    @Override
    public AnchorLivesRoom queryByAnchorId(Long anchorId) {
        AnchorLivesRoom anchorLivesRoom = getOne(Wrappers.<AnchorLivesRoom>lambdaQuery().eq(AnchorLivesRoom::getAnchorId, anchorId).last("limit 1"));
        return null == anchorLivesRoom ? initLivesRoom(anchorId) : anchorLivesRoom;
    }

    /**
     * 根据直播间号查询直播间
     *
     * @param roomNum
     */
    @Override
    public AnchorLivesRoom queryByRoomNum(String roomNum) {
        return getOne(Wrappers.<AnchorLivesRoom>lambdaQuery().eq(AnchorLivesRoom::getLivesRoomNum, roomNum).last("limit 1"));
    }

    /**
     * 判断正在直播
     *
     * @param roomNum
     */
    @Override
    public AnchorLivesRoom checkIsLive(String roomNum) {
        AnchorLivesRoom anchorLivesRoom = queryByRoomNum(roomNum);
        if (anchorLivesRoom==null){
            throw new QysException(MessageUtils.message("直播间不存在"));
        }
        if (anchorLivesRoom.getLiveStatus()==1){
            throw new QysException(MessageUtils.message("直播间尚未开播"));
        }
        return anchorLivesRoom;
    }

    @Override
    public AnchorLivesRoom getRoomByUserId(Long userId) {
        H2Anchor anchor = anchorMapper.selectOne(Wrappers.<H2Anchor>lambdaQuery().eq(H2Anchor::getUserId, userId).eq(H2Anchor::getIsDelete, 0));
        if(anchor==null){
            return null;
        }
        return this.getOne(Wrappers.<AnchorLivesRoom>lambdaQuery().eq(AnchorLivesRoom::getAnchorId, anchor.getId()));
    }

    @Override
    public H2AppUser getUserByAnchorId(Long anchorId) {
        H2Anchor anchor = anchorMapper.selectById(anchorId);
        if(anchor == null){
            return null;
        }
        return appUserService.getById(anchor.getUserId());
    }

    @Override
    public IPage<AnchorLivesVO> getAnchorLivesRoom(AnchorLivesDTO dto) {
        LambdaQueryWrapper<AnchorLivesRoom> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(null != dto.getLiveStatus(),AnchorLivesRoom::getLiveStatus, dto.getLiveStatus());
        queryWrapper.eq(null != dto.getStatus(),AnchorLivesRoom::getStatus, dto.getStatus());
        queryWrapper.orderByDesc(AnchorLivesRoom::getCreateTime);
        return page(new Page<>(dto.getPageNum(), dto.getPageSize()), queryWrapper).convert(e -> {
            AnchorLivesVO anchorLivesVO=new AnchorLivesVO();
            BeanUtils.copyProperties(e,anchorLivesVO);
            //返回基本信息
            H2AppUser user = this.getUserByAnchorId(e.getAnchorId());
            anchorLivesVO.setUserId(Long.valueOf(user.getId()));
            anchorLivesVO.setAvatar(user.getAvatar());
            anchorLivesVO.setNickName(user.getNickName());
            //返回粉丝数量
            H2Anchor anchor = anchorMapper.selectById(e.getAnchorId());
            anchorLivesVO.setFans(anchor.getFansNumber());
            //直播间截图
            if(anchorLivesVO.getLiveStatus() == (byte)2){
                ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).minusMinutes(1);
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm");
                String img = String.format("%s/%s-%s.png", "lives_room_img", anchor.getUserId(), zdt.format(formatter));
                anchorLivesVO.setLivesImage(img);
            }
            //返回本场直播名称
            AnchorLivesSession livesSession = livesSessionMapper.selectOne(Wrappers.<AnchorLivesSession>lambdaQuery()
                    .eq(AnchorLivesSession::getAnchorId, e.getAnchorId())
                    .eq(AnchorLivesSession::getLivesStatus, 2));
            if(livesSession != null){
                anchorLivesVO.setLivesSessionName(livesSession.getLivesSessionName());
            }
            return anchorLivesVO;
        });
    }

    @Override
    public void recordViewing(Long userId) {
        baseMapper.recordView(userId);
    }

    @Override
    public int getUserViewTime(Long userId) {
        return baseMapper.selectUserViewTime(userId);
    }

    private String getLivesRoomNum() {
        String roomNum = RandomUtil.randomNumbers(8);
        Long count = baseMapper.selectCount(Wrappers.<AnchorLivesRoom>lambdaQuery().eq(AnchorLivesRoom::getLivesRoomNum, roomNum));
        if (count > 0) {
            return getLivesRoomNum();
        }
        return roomNum;
    }
}
